package org.raymond.iworks.study.netty.nio;

import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;

/**
 * @author raymond
 * @version V1.0
 * @Description: TODO
 */
public class ByteBufferTest {
    /**
     * 创建方式:
     * 1, JVM堆内内存块Buffer(非直接缓冲区)
     * 1)
     * ByteBuffer byteBuffer1 = ByteBuffer.allocate(1024);
     *
     * 2)
     * String msg = "学习NIO: bytebuffer!";
     * 包装一个byte[]数组获得一个Buffer，实际类型是HeapByteBuffer
     * ByteBuffer byteBuffer2 = ByteBuffer.wrap(msg.getBytes());
     *
     * 2, 堆外内存块Buffer(直接缓冲区)
     * ByteBuffer byteBuffer3 = ByteBuffer.allocateDirect(1024);
     *
     * 区别:
     * HeapByteBuffer所创建的字节缓冲区就是在JVM堆中的,即JVM内部所维护的字节数组.
     * DirectByteBuffer是直接操作操作系统本地代码创建的内存缓冲数组.
     *
     * 最大的不同在于直接缓冲区不需要再把内容copy到物理内存中,而是从应用程序直接写入物理磁盘或者网卡.这就大大地提高了性能
     *
     * 缓存区是双向的,既可以往缓冲区写入数据,也可以从缓冲区读取数据.但是不能同时进行,需要切换.(flip)
     *
     * 使用场景:
     * DirectByteBuffer的使用场景:
     * java程序向本地磁盘或socket传输数据
     * 大文件对象可以使用.不会受到堆内存大小的限制.
     * 不需要频繁创建,生命周期较长的情况,能重复使用的情况
     *
     * HeapByteBuffer的使用场景:
     * 除了以上的场景外,其他情况还是建议使用HeapByteBuffer,没有达到一定的量级,实际上使用DirectByteBuffer是体现不出优势的
     *
     * 缓冲区的3个关键属性:
     * position, 位置,默认是从第一个开始
     *
     * limit, 限制,不能读取或者写入的位置索引.
     * limit的作用就是记录写入数据的位置,当读取数据时,就知道读到哪个位置结束
     *
     * capacity, 容量, 缓冲区所包含的元素的数量
     *
     *
     */
    public static void main(String[] args) {
        // bytes.length=22
        String msg = "学习NIO: bytebuffer!";
        // position=0,limit=1024,capacity=1024
        ByteBuffer byteBuffer = ByteBuffer.allocate(1024);
        byte[] bytes = msg.getBytes(StandardCharsets.UTF_8);
        // 将msg bytes写入到byteBuffer中, put进多少bytes,position就会增加多少.
        // position=22,limit=1024,capacity=1024
        byteBuffer.put(bytes);
        // 关键一步,切换成读模式. pos被初始化为0, 原来pos的值被赋给limit.
        // position=0,limit=22,capacity=1024
        byteBuffer.flip();
        // 创建一个byte数组,用于存储读到的数据
        byte[] tempBytes = new byte[bytes.length];
        int i=0;
        // 如果还有数据未读,则继续, 求布尔值 position<limit
        while(byteBuffer.hasRemaining()){
            // 获取buffer中的数据. position = position+1
            byte b = byteBuffer.get();
            // 放入到临时数组中
            tempBytes[i] = b;
            i++;
        }
        // position=22,limit=22,capacity=1024
        System.out.println("读取到的数据: "+new String(tempBytes, StandardCharsets.UTF_8));
    }
}
